/*
 * Copyright (c) 2016 CGT Co., Ltd.
 *
 * Authors: Robin Lee <lixiangbin@china-dsp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program;
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/socket.h>

#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>

#include <termios.h>
#include <netinet/in.h>

#include "cetc14-iic.h"
/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * global vars
 */
//i2c address of sdi
#define FP_DEV1 "/sys/class/i2c-dev/i2c-0/device/0-0001/eeprom"
#define FP_DEV2 "/sys/class/i2c-dev/i2c-0/device/0-0002/eeprom"
#define FP_DEV3 "/sys/class/i2c-dev/i2c-0/device/0-0004/eeprom"

static int global_fd1 = -1;
static int global_fd2 = -1;
static int global_fd3 = -1;

//operations of sdi
//open fd
int fd_initial(int num)
{
	int fd = -1;
	/*
		Open modem device for reading and writing and not as controlling tty
		because we don't want to get killed if linenoise sends CTRL-C.
	*/
	if(num==0)
	{
//		printf("Open '%s' .. ", FP_DEV1);
		fd = open(FP_DEV1, O_RDWR );
	}
	else if(num==1)
	{
//		printf("Open '%s' .. ", FP_DEV2);
		fd = open(FP_DEV2, O_RDWR );
	}
	else if(num==2)
	{
//		printf("Open '%s' .. ", FP_DEV3);
		fd = open(FP_DEV3, O_RDWR );
	}
	else
	{
		printf("Open error.\n");
		return -1;
	}

	if (fd <0) {
		printf("failed (err = %d)\n", fd);
		return -1;
	}
//	printf("Done\n");
	return fd;
}

//close fd
int fd_exit(int num)
{
	if(num==0)
	{
		close(global_fd1);
//		printf("Close '%s' .. ", FP_DEV1);
	}
	else if(num==1)
	{
		close(global_fd2);
//		printf("Close '%s' .. ", FP_DEV2);
	}
	else if(num==2)
	{
		close(global_fd3);
//		printf("Close '%s' .. ", FP_DEV3);
	}
//	printf("Done\n");
	return 0;
}

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * get_sdi_reg, set_sdi_reg
 */
//get sdi reg by i2c
unsigned int get_sdi_reg(int num,unsigned int offset)
{
	unsigned int value = 0xffff;
	unsigned int ans=0;
	int fd=-1;
	if(num==0)
	{
		fd=global_fd1;
	}
	else if(num==1)
	{
		fd=global_fd2;
	}
	else if(num==2)
	{
		fd=global_fd3;
	}
	else
	{
		printf("get_sdi_reg::Invalid param !\n");
		return 0;
	}

	if (fd<0) {
		printf("Invalid device handle !\n");
		return value;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return value;
	}

	if ( read(fd, &value, sizeof(value)) != sizeof(value)) {
		printf("failed for read from offset 0x%x !\n", offset);
		return value;
	}
	ans=htonl(value);
	return ans;
}

//set sdi reg by i2c
void set_sdi_reg(int num,unsigned int offset, unsigned int data)
{
	unsigned int value = htonl(data);
	int fd=-1;
	if(num==0)
	{
		fd=global_fd1;
	}
	else if(num==1)
	{
		fd=global_fd2;
	}
	else if(num==2)
	{
		fd=global_fd3;
	}
	else
	{
		printf("set_sdi_reg::Invalid param !\n");
		return;
	}
	if (fd<0) {
		printf("Invalid device handle !\n");
		return ;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return ;
	}

	if ( write(fd, &value, sizeof(value)) != sizeof(value)) {
		printf("failed for write from offset 0x%x !\n", offset);
		return ;
	}
	return ;
}

unsigned int regtoul(const char *str)
{
	int cbase = 10;
	if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) {
		cbase = 16;
	}
	return strtoul(str, NULL, cbase);
}

//init sdi
int Init_sdi(int num)
{
	if(num==0)
	{
		global_fd1 = fd_initial(0);
	}
	else if(num==1)
	{
		global_fd2 = fd_initial(1);
	}
	else if(num==2)
	{
		global_fd3 = fd_initial(2);
	}
	return 0;
}

#if 0
int main(int argc, char **argv)
{
	int baseaddr=0;
	int offset=0;
	int port=0;
	int temp1=0,temp2=0,temp3=0,temp4=0;
	int writeval=0;
	int val=0;
	int true_offset=0;

	//init sdi
	Init_sdi();

	if(argc < 9)
	{
		printf("input error\n");
		exit(1);
	}
	baseaddr = strtoul(argv[1], 0, 0);
	offset = strtoul(argv[2], 0, 0);
	port = strtoul(argv[3], 0, 0);

	temp1 = strtoul(argv[4], 0, 0);
	temp2 = strtoul(argv[5], 0, 0);
	temp3 = strtoul(argv[6], 0, 0);
	temp4 = strtoul(argv[7], 0, 0);

	writeval = strtoul(argv[8], 0, 0);
	val= strtoul(argv[9], 0, 0);

	//get sdi reg address
	true_offset=baseaddr+offset*port+temp1+temp2+temp3+temp4;

	//set sdi chip reg
	set_sdi_reg(0,true_offset,writeval);

	fd_exit(global_fd,1);

	return 0;
}
#endif

int iic_access(unsigned int sdiIndex, unsigned char iic_slave_addr, unsigned int reg_offset, \
			unsigned int *reg_val, unsigned int rw_flag)
{
	int writeval=0;
	int readval=0;
	int true_offset=0;

	//init sdi
	Init_sdi(sdiIndex);


//	if(argc < 9)
//	{
//		printf("input error\n");
//		exit(1);
//	}
//	baseaddr = strtoul(argv[1], 0, 0);
//	offset = strtoul(argv[2], 0, 0);
//	port = strtoul(argv[3], 0, 0);
//
//	temp1 = strtoul(argv[4], 0, 0);
//	temp2 = strtoul(argv[5], 0, 0);
//	temp3 = strtoul(argv[6], 0, 0);
//	temp4 = strtoul(argv[7], 0, 0);
//
//	writeval = strtoul(argv[8], 0, 0);
//	val= strtoul(argv[9], 0, 0);

	
	if(rw_flag)
	{
	true_offset = reg_offset;
	//set sdi chip reg
	readval = get_sdi_reg(sdiIndex,true_offset);
	*reg_val = readval;
//	printf("iic read: reg: %#x  val:%#x\n", true_offset, *reg_val);
	}
	else
	{
	//get sdi reg address
//	true_offset=baseaddr+offset*port+temp1+temp2+temp3+temp4;
	true_offset = reg_offset;
	writeval = *reg_val;
	//set sdi chip reg
	set_sdi_reg(sdiIndex,true_offset,writeval);
	}

	fd_exit(sdiIndex);

	return 0;
}
#if 0
void main(int argc, char **argv)
{
	unsigned int reg_offset, reg_val, rw_flag;

	reg_offset = strtoul(argv[1], 0, 0);
	reg_val = strtoul(argv[2], 0, 0);
	rw_flag = strtoul(argv[3], 0, 0);
	iic_access(0, 0, reg_offset, &reg_val, rw_flag);
	if(rw_flag)
	printf("iic read: reg: %#x  val:%#x\n", reg_offset, reg_val);
}
#endif
